package cn.wgx.module.base.services;

import cn.wgx.commons.util.*;
import cn.wgx.module.base.entity.BaseEntity;
import cn.wgx.module.base.entity.mapper.BaseUtilMapper;
import com.google.common.collect.Lists;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.*;
import java.util.*;


public abstract class BaseService<T extends BaseEntity> extends BaseLogger {


    public static final String cacheName = "sysCache";

    protected List emptyList = new ArrayList();

    protected Object emptyObject = new Object();

    protected BaseEntity baseEntity;

    public int updateClick(int id, String tableName) {
        if (tableName == null) {
            return 0;
        }
        Object o = SpringContextHolder.getBean("baseUtilMapper");
        if (o instanceof BaseUtilMapper) {
            o = (BaseUtilMapper) o;
            return ((BaseUtilMapper) o).updateByPrimaryKey(tableName, id);
        }
        return 0;
    }

    public String getCachePreKey() {
        return "CACHE_" + this.getClass().getName() + "_";
    }

    // addCustomSQL(criteria, " t.pass%2 = ", "1");
    protected int addCustomSQL(Object criteriaObj, String condition, String value) {
        if (!validateSQL(condition)) {
            //验证sql是否有注入字段
            return 0;
        }
        Map<String, Object> param = new HashMap<>();
        param.put(condition, value);
        return doAddParam(criteriaObj, param);
    }

    protected boolean validateSQL(String sql) {
        //todo 完整验证sql注入
        if (StringUtils.isNotBlank(sql) && !sql.contains("--")) {
            return true;
        }
        return false;
    }

    /**
     * 反射加公共sql参数,确保包含字段createDate
     * 1. 时间范围
     *
     * @param t
     * @param criteriaObj
     */
    protected <E extends BaseEntity> void addPublicCondition(E t , Object criteriaObj) {
        Map<String, Object> param = new HashMap<>();
        if (t.get_startDate() != null) {
            param.put(" t.createDate >= ", t.get_startDate());
        }
        if (t.get_endDate() != null) {
            param.put(" t.createDate < ", DateUtils.getNextDateZero(t.get_endDate()));
        }
        if (!param.isEmpty()) {
            doAddParam(criteriaObj, param);
        }
    }

    private int doAddParam(Object criteriaObj, Map<String, Object> param) {
        Class<?> aClass = criteriaObj.getClass();
        int n = 0;
        try {
            Field field = ReflectionUtils.getField(aClass, "criteria");
            if (field != null) {
                //判断field类型
                Class<?> type = field.getType();
                Type genericType = field.getGenericType();
                //判断是否是泛型类
                if (type.equals(List.class)
                        && genericType instanceof ParameterizedType) {
                    field.setAccessible(true);
                    List arrayList = (List) field.get(criteriaObj);
                    Class<?> actualTypeArguments = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
                    Constructor<?> constructor = actualTypeArguments.getDeclaredConstructor(String.class, Object.class);
                    constructor.setAccessible(true);
                    for (Map.Entry entry : param.entrySet()) {
                        Object o = constructor.newInstance(entry.getKey(), entry.getValue());
                        arrayList.add(o);
                        n++;
                    }
                }
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return n;
    }

    /**
     * 通过反射获取 对象指定field list
     * @param list
     * @param fieldName
     * @param <E>
     * @return
     */
    protected <E> List<Integer> getIntegerIdList(List<E> list, String fieldName) {
        ArrayList<Integer> arrayList = Lists.newArrayList();
        if (list != null) {
            Field field1 = null;
            try {
                if (!list.isEmpty()) {
                    field1 = list.get(0).getClass().getDeclaredField(fieldName);
                    field1.setAccessible(true);
                }
                for (E o : list) {
                    Object o1 = field1.get(o);
                    if (o1 instanceof Integer) {
                        arrayList.add((Integer) o1);
                    }else{
                        break;
                    }
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return arrayList;
    }




    /**
     * 过滤参数
     *
     * @param t
     * @param isInsert
     */
    protected void filter(T t, boolean isInsert) {
        if (t == null) return;
        Integer userId = 0;
        Date date = new Date();
        if (isInsert) {
            t.setCreateUserId(userId);
            t.setCreateDate(date);
        } else {
            t.setCreateUserId(null);
            t.setCreateDate(null);
            t.setUpdate(true);
        }
        t.setUpdateUserId(userId);
        t.setUpdateDate(date);
        t.setInsert(isInsert);
    }


    protected T wrap(T t) {
        return t;
    }


    @Transactional(readOnly = true)
    public List wrap(List<T> list) {
        if (null != list && !list.isEmpty()) {
            ArrayList arrayList = new ArrayList(list.size());
            for (T t : list) {
                T wrap = wrap(t);
                if (null != wrap) {
                    arrayList.add(wrap);
                }
            }
            return arrayList;
        } else
            return emptyList;
    }

//
//    public abstract Object getObjectById(int id);
//
//    public abstract List<Object> getObjectList(int l, int n);
//
//    public abstract List<Object> getObjectListByKeyWord(String vedioKeyWord, int l, int n);
//
//    public abstract int addObject(Object object);
//
//    public abstract int delObjectById(int id);
//
//    public abstract int modifyObject(Object object);
//
//    public abstract int updateClick(int id);
}
